﻿#region Using directives

using System;
using System.Xml;
using System.Text;
using System.DirectoryServices;
using MCMLXVII.BackEnd.Data.SystemDatabase;

#endregion

namespace MCMLXVII.SubSystems.Security.DirectoryServices
{
    public class ActiveDirectory: IDirectoryService, IDirectoryTreeBrowser 
    {
        public ActiveDirectory()
        {

        }

        #region IDirectoryService Members

        public bool LogonUser(string FQDN, string NetBiosName, string DirConfigInfo, string UserName, string Password)
        {
            try
            {
                DirectoryEntry mDirEntry = new DirectoryEntry("LDAP://" + FQDN, UserName, Password, AuthenticationTypes.Secure);
                return true;
            }
            catch
            {
                return false;
            }
        }

        public XmlDocument GetDirectoryUsersList(string Path, XmlDocument DirConfigInfo, string NameFilter)
        {
            string UserName = "";
            string Password = "";
            if (DirConfigInfo.SelectSingleNode("Info/UserName") != null)
                UserName = DirConfigInfo.SelectSingleNode("Info/UserName").InnerText;
            if (DirConfigInfo.SelectSingleNode("Info/Password") != null)
                Password = DirConfigInfo.SelectSingleNode("Info/Password").InnerText;

            StringBuilder sb = new StringBuilder();
            sb.Append("<Root Path=\"" + Path + "\">");



            DirectoryEntry DirEntry;
            if (UserName != "")
                DirEntry = new DirectoryEntry(Path, UserName, Password);
            else
                DirEntry = new DirectoryEntry(Path, UserName, Password);
            DirectorySearcher DirSearcher = new DirectorySearcher(DirEntry);
            DirSearcher.SearchScope = SearchScope.OneLevel;
            DirSearcher.Filter = "((objectClass=user))"; //Implement filter by name
            DirSearcher.ServerTimeLimit = TimeSpan.FromSeconds(200);
            DirSearcher.ClientTimeout = TimeSpan.FromSeconds(200);
            DirSearcher.Sort = new SortOption("Name", SortDirection.Ascending);

            //SearchResultCollection Results;
            try
            {
                foreach (SearchResult Res in DirSearcher.FindAll())
                {
                    sb.Append("<Node Name=\"" + Res.Properties["Name"][0] + "\" Path=\"" + Res.Path + "\" ID=\""+Res.Properties["objectsid"][0].ToString() +"\" LogonName=\""+Res.Properties["samaccountname"][0] + "\" >");
                    //Append property Maps
                    foreach(XmlNode node in DirConfigInfo.SelectSingleNode("Info/AditionalMappings"))
                    {
                        try
                        {
                            sb.Append("<Property Name=\"" + node.Attributes.GetNamedItem("destination").Value + "\" Value=\"" + Res.Properties[node.Attributes.GetNamedItem("source").Value][0].ToString() + "\" />");
                        }
                        catch
                        { 
                            // nothing to do, the property is not accesible or not applicable to the object class
                        }
                    }
                    sb.Append("</Node>");

                }
            }
            catch // (Exception ex)
            {
                //nothing to do, unable to access directory object information
            }

            sb.Append("</Root>");
            XmlDocument xDoc = new XmlDocument();
            xDoc.LoadXml(sb.ToString());
            return xDoc;
        }


        public XmlDocument GetDirectoryGroupsList(string Path, XmlDocument DirConfigInfo, string NameFilter)
        {
            string UserName = "";
            string Password = "";
            if (DirConfigInfo.SelectSingleNode("Info/UserName") != null)
                UserName = DirConfigInfo.SelectSingleNode("Info/UserName").InnerText;
            if (DirConfigInfo.SelectSingleNode("Info/Password") != null)
                Password = DirConfigInfo.SelectSingleNode("Info/Password").InnerText;

            StringBuilder sb = new StringBuilder();
            sb.Append("<Root Path=\"" + Path + "\">");

            DirectoryEntry DirEntry;
            if (UserName != "")
                DirEntry = new DirectoryEntry(Path, UserName, Password);
            else
                DirEntry = new DirectoryEntry(Path, UserName, Password);
            DirectorySearcher DirSearcher = new DirectorySearcher(DirEntry);
            DirSearcher.SearchScope = SearchScope.OneLevel;
            DirSearcher.Filter = "((objectClass=group))"; //Implement filter by name
            DirSearcher.ServerTimeLimit = TimeSpan.FromSeconds(200);
            DirSearcher.ClientTimeout = TimeSpan.FromSeconds(200);
            DirSearcher.Sort = new SortOption("Name", SortDirection.Ascending);

            //SearchResultCollection Results;
            try
            {
                foreach (SearchResult Res in DirSearcher.FindAll())
                {
                    sb.Append("<Node Name=\"" + Res.Properties["Name"][0] + "\" Path=\"" + Res.Path + "\" ID=\"" + Res.Properties["objectsid"][0].ToString() + "\" LogonName=\"" + Res.Properties["samaccountname"][0] + "\" >");
                    //Append property Maps
                    foreach (XmlNode node in DirConfigInfo.SelectSingleNode("Info/AditionalMappings"))
                    {
                        try
                        {
                            sb.Append("<Property Name=\"" + node.Attributes.GetNamedItem("destination").Value + "\" Value=\"" + Res.Properties[node.Attributes.GetNamedItem("source").Value][0].ToString() + "\" />");
                        }
                        catch
                        {
                            // nothing to do, the property is not accesible or not applicable to the object class
                        }
                    }
                    sb.Append("</Node>");

                }
            }
            catch // (Exception ex)
            {
                //nothing to do, unable to access directory object information
            }

            sb.Append("</Root>");
            XmlDocument xDoc = new XmlDocument();
            xDoc.LoadXml(sb.ToString());
            return xDoc;
        }

        public string GetRoot(string FQDN, string NetbiosName)
        {
            return "LDAP://" + FQDN;
        }

        #endregion

        #region IDirectoryTreeBrowser Members

        public XmlDocument GetDirectoryTree(string FQDN, string NetbiosName, System.Xml.XmlDocument DirConfigInfo, int MaxDeepLevel)
        {
            string UserName = "";
            string Password = "";
            if (DirConfigInfo.SelectSingleNode("Info/UserName") != null)
                UserName = DirConfigInfo.SelectSingleNode("Info/UserName").InnerText ;
            if (DirConfigInfo.SelectSingleNode("Info/Password") != null)
                Password = DirConfigInfo.SelectSingleNode("Info/Password").InnerText ;

            
            string dsPath = "LDAP://" + FQDN;
            StringBuilder sb = new StringBuilder();
            sb.Append("<Root Name=\"" + FQDN + "\" Path=\"" + dsPath + "\"");
            if (MaxDeepLevel > 1)
            {
                sb.Append(" Expanded=\"True\">");
                GetChildren(dsPath, sb, MaxDeepLevel - 1, UserName, Password );
            }
            else
            {
                sb.Append(" Expanded=\"False\">");
            }


            sb.Append("</Root>");
            XmlDocument xDoc = new XmlDocument();
            xDoc.LoadXml(sb.ToString());
            return xDoc;

        }

        private void GetChildren( string dsPath, StringBuilder sb, int MaxDeepLevel, string UserName, string Password)
        {
            DirectoryEntry DirEntry;
            if (UserName != "")
                DirEntry = new DirectoryEntry(dsPath, UserName, Password);              
            else
                DirEntry = new DirectoryEntry(dsPath);
            DirectorySearcher DirSearcher = new DirectorySearcher(DirEntry);
            DirSearcher.SearchScope = SearchScope.OneLevel;
            DirSearcher.Filter = "(|(objectClass=container)(objectClass=organizationalUnit))";
            DirSearcher.ServerTimeLimit = TimeSpan.FromSeconds(200);
            DirSearcher.ClientTimeout = TimeSpan.FromSeconds(200);
            DirSearcher.Sort = new SortOption("Name", SortDirection.Ascending);
                
                //SearchResultCollection Results;
                try
                {
                    foreach(SearchResult Res in DirSearcher.FindAll())
                    {
               

                        if (Res.Path != dsPath) 
                        {
                            bool aux = ((string)Res.Properties["objectclass"][1] == "organizationalUnit");
                            if (!aux)
                                try {
                                     aux = !(bool)Res.Properties["showinadvancedviewonly"][0];
                                }
                                catch
                                {
                                     aux = true;
                                }
                            if (aux)                           
                            {
                                sb.Append("<Node Name=\"" + Res.Properties["Name"][0] + "\" Path=\"" + Res.Path + "\" Expanded=\"");
                                if (MaxDeepLevel > 1)
                                {
                                    sb.Append("True\">");
                                    GetChildren(Res.Path, sb, MaxDeepLevel - 1, UserName, Password );
                                    sb.Append("</Node>");
                                }
                                else
                                {
                                    sb.Append("False\"/>");
                                }
                            }
                        }
                    }
                }
                catch // (Exception ex)
                {
                    //TODO
                }

        }

        public System.Xml.XmlDocument GetNodeChildren(string FQDN, string NetbiosName, System.Xml.XmlDocument DirConfigInfo, string NodePath, int MaxDeepLevel)
        {
            throw new NotImplementedException();
        }

#endregion
    }
}
